<template>
  <n-split direction="horizontal" :min="0.15" :max="0.8" default-size="200px" v-if="props.type == 1">
    <template #1>
      <div class="fold">
        <div class="topbar">
          <el-tooltip class="box-item" effect="dark" content="创建文件" placement="bottom">
            <i class="iconfont icon-chuangjianrenwu" @click="addRootFile()"></i>
          </el-tooltip>
          <el-tooltip class="box-item" effect="dark" content="创建文件夹" placement="bottom">
            <i class="iconfont icon-xinjianwenjianjia" @click="addRootFileFlod()"></i>
          </el-tooltip>
        </div>
        <el-tree :allow-drop="allowDrop" :allow-drag="allowDrag" :data="fileTree" draggable default-expand-all
          node-key="id" @node-drag-start="handleDragStart" @node-drag-enter="handleDragEnter"
          @node-drag-leave="handleDragLeave" @node-drag-over="handleDragOver" @node-drag-end="handleDragEnd"
          @node-click="handleNodeClick" @node-drop="handleDrop" :highlight-current="true">
          <template #default="{ node, data }">
            <div class="custom-tree-node" @contextmenu.prevent="showContextMenu($event, node)">
              <el-input ref="inputRef" v-model="node.data.label" v-if="node.checked" @blur="unShowEditInput(node)"
                @focus="() => { tempText = node.data.label }"></el-input>
              <span v-else>
                <i class="iconfont icon-wenjian" v-if="node.data.type == 'file'"></i>
                <i class="iconfont icon-wj-wjj" v-if="node.data.type == 'folder'"></i>
                {{ node.label }}
              </span>
            </div>
          </template>
        </el-tree>
        <div v-if="isMenuVisible" class="context-menu" :style="{ top: menuTop + 'px', left: menuLeft + 'px' }">
          <ul>
            <li v-for="(item, index) in menuList" :key="index" @click="() => { item.func() }">{{ item.label }}</li>
          </ul>
        </div>
      </div>
    </template>
    <template #2>
      <codeMirrorVue v-model:propCode="curShowCode" v-if="curNode && curNode.type == 'file'"></codeMirrorVue>
    </template>
  </n-split>
  <codeMirrorVue v-model:propCode="singleTypeCode" v-else></codeMirrorVue>
</template>

<script setup>
import { ref, onMounted, onUnmounted, nextTick, watch, reactive } from 'vue'
import { validateFileFlodName, validateFileName } from '@/utils/file'
import { ElMessage } from "element-plus"
import codeMirrorVue from "@/components/ojComponents/compiler/codeMirrorVue.vue"
import { LangeuageConf } from '@/pages/ojPage/quiz/config'

const emits = defineEmits(['dataChange'])
const props = defineProps({
  // 0 单类 1多类
  type: {
    type: Number,
    default: 0
  },
  data: {
    type: Object
  }
})

const singleTypeCode = reactive({
  code: ''
})
watch(() => singleTypeCode.code, () => {
  let { code } = singleTypeCode
  emits('dataChange', {
    language: props.data.language,
    format: [
      {
        "label": LangeuageConf[props.data.language],
        "children": [],
        "type": "file",
        "code": code
      }
    ],
    code: props.data.code
  })
}, { deep: true })

// 菜单项-源数据
const menuOrigin = [
  {
    label: '新建文件',
    func: () => {
      appFile()
    }
  },
  {
    label: '新建文件夹',
    func: () => {
      appFileFloder()
    }
  },
  {
    label: '重命名',
    func: () => {
      renameNode()
    }
  },
  {
    label: '删除',
    func: () => {
      removeFile()
    }
  },
]
// 菜单项
const menuList = ref(menuOrigin)


watch(() => props.data.format, () => {
  if (props.type) {
    fileTree.value = props.data.format instanceof Array ? props.data.format : []
  }
})

onMounted(() => {
  if(props.type == 0){
    singleTypeCode.code = props.data.format[0].code
  }else{
    fileTree.value = props.data.format
  }
})
// 文件树渲染数据
const fileTree = ref([])

// 当前选中节点 普通格式
const curNode = ref(null)
// 当前选中节点 复杂格式
const curNodeWithParent = ref(null)
// 当前代码
const tempText = ref('')

// 菜单可见/位置
const isMenuVisible = ref(false)
const menuTop = ref(0)
const menuLeft = ref(0)

/**
 * 展示菜单
 * @param event 
 * @param node 
 */
const showContextMenu = (event, node) => {
  curNodeWithParent.value = node
  curNode.value = node.data
  if (node.data.type === 'file') {
    menuList.value = menuOrigin.filter(item => (item.label !== '新建文件夹' && item.label !== '新建文件'))
  } else {
    menuList.value = menuOrigin
  }
  menuTop.value = event.clientY
  menuLeft.value = event.clientX
  isMenuVisible.value = true
}

/**
 * 节点点击事件
 * @param data 
 */
const handleNodeClick = (data) => {
  isMenuVisible.value = false
  curNode.value = data
}

const handleDragStart = (node, ev) => {
  // console.log('drag start', node)
}
const handleDragEnter = (
  draggingNode,
  dropNode,
  ev
) => {
  // console.log('tree drag enter:', dropNode.label)
}
const handleDragLeave = (
  draggingNode,
  dropNode,
  ev
) => {
  // console.log('tree drag leave:', dropNode.label)
}
const handleDragOver = (draggingNode, dropNode, ev) => {
  // console.log('tree drag over:', dropNode.label)
}
const handleDragEnd = (
  draggingNode,
  dropNode,
  dropType,
  ev
) => {
  // console.log('tree drag end:', dropNode && dropNode.label, dropType)
}
const handleDrop = (
  draggingNode,
  dropNode,
  dropType,
  ev
) => {
  // console.log('tree drop:', dropNode.label, dropType)
}
const allowDrop = (draggingNode, dropNode, type) => {
  // 仅允许拖拽file类型
  if (dropNode.data.type === 'file') {
    return type !== 'inner'
  } else {
    return true
  }
}
const allowDrag = (draggingNode) => {
  return draggingNode.data.type === 'file'
}

const hideContextMenu = () => {
  isMenuVisible.value = false
}

onMounted(() => {
  window.addEventListener('click', hideContextMenu)
  window.addEventListener('wheel', hideContextMenu)
})

// 组件卸载前移除事件监听器
onUnmounted(() => {
  window.removeEventListener('click', hideContextMenu)
  window.removeEventListener('wheel', hideContextMenu)
})

const inputRef = ref(null)


/**
 * 重命名文件
 */
const renameNode = () => {
  curNodeWithParent.value.checked = true
  setTimeout(() => {
    inputRef.value?.focus()
  }, 80)
}

/**
 * 删除文件/文件夹
 */
const removeFile = () => {
  const parent = curNodeWithParent.value.parent
  // console.log(parent)
  let children = []
  // 顶级节点没有children属性
  if (parent.level == 0) {
    children = parent.data
  } else {
    children = parent.data.children
  }
  const childNodes = parent.childNodes
  const index = childNodes.findIndex((d) => d.id === curNode.value.$treeNodeId)
  const index2 = children.findIndex((d) => d.$treeNodeId === curNode.value.$treeNodeId)
  childNodes.splice(index, 1)
  children.splice(index2, 1)
  curShowCode.code = ''
}

/**
 * 根节点添加文件
 */
const addRootFile = () => {
  fileTree.value.push({
    label: '新建文件',
    children: [],
    type: 'file',
    code: ''
  })
}

/**
 * 根节点添加文件夹
 */
const addRootFileFlod = () => {
  fileTree.value.push({
    label: '新建文件夹',
    children: [],
    type: 'folder'
  })
}

/**
 * 失焦隐藏输入框
 * @param node 
 */
const unShowEditInput = (node) => {
  let flag = true
  if (node.data.type === 'folder') {
    flag = validateFileFlodName(node.data.label)
  } else {
    flag = validateFileName(node.data.label)
  }
  if (flag) {
    node.checked = false
  } else {
    node.data.label = tempText.value || 'ErrorFileName'
    node.checked = false
    ElMessage.error("文件名称格式错误")
  }
}

/**
 * 非根节点添加文件夹
 */
const appFileFloder = () => {
  const cur = curNodeWithParent.value
  cur.data.children.push({
    label: '',
    children: [],
    type: 'folder',
  })
  setTimeout(() => {
    curNodeWithParent.value = curNodeWithParent.value.childNodes[curNodeWithParent.value.childNodes.length - 1]
    curNodeWithParent.value.checked = true
    nextTick(() => {
      inputRef.value?.focus()
    })
  }, 100)
}

/**
 * 非根节点添加文件
 */
const appFile = () => {
  const cur = curNodeWithParent.value
  cur.data.children.push({
    label: '',
    children: [],
    type: 'file',
    code: ''
  })
  setTimeout(() => {
    curNodeWithParent.value = curNodeWithParent.value.childNodes[curNodeWithParent.value.childNodes.length - 1]
    curNodeWithParent.value.checked = true
    nextTick(() => {
      inputRef.value?.focus()
    })
  }, 100)
}

const curShowCode = reactive({
  code: ''
})
watch(() => curNode.value, (newV) => {
  curShowCode.code = newV.code
})
watch(() => curShowCode.code, (newV) => {
  curNode.value.code = newV
})
watch(() => fileTree.value, (newV) => {
  emits('dataChange', {
    language: props.data.language,
    format: newV,
    code: props.data.code
  })
}, {
  deep: true
})
</script>

<style lang="less" scoped>
.fold {
  height: 100%;
}

.custom-tree-node {
  display: flex;
  flex-wrap: nowrap;
  overflow: hidden;
  width: 100%;
  height: 100%;
}

.topbar {
  display: flex;
  justify-content: right;
  gap: 0.5rem;
  padding: 2px 4px;
  height: 30px;

  .iconfont {
    height: 80%;
    cursor: pointer;
  }
}

.context-menu {
  position: fixed;
  background-color: white;
  border: 1px solid #ccc;
  z-index: 9999;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  border-radius: 8px;
  padding: 2px;

  ul {
    list-style: none;
    margin: 0;
    padding: 0;

    li {
      padding: 2px 12px;
      cursor: pointer;
      border-radius: 2px;

      &:hover {
        background-color: #cfcfcf;
      }
    }
  }
}
</style>